#pragma once

#include "../communal/Communication.hpp"
#include "../communal/Message.hpp"
#include <future>

namespace xu
{
    namespace client
    {
        class Requestor
        {
        public:
            using Ptr = std::shared_ptr<Requestor>;
            using Callback = std::function<void(const xu::BaseMessage::Ptr &)>;
            using OfflineCallback = std::function<void(const Address&)>;
            using Async = std::future<xu::BaseMessage::Ptr>;
            struct RequestDescribe
            {
                using Ptr = std::shared_ptr<RequestDescribe>;
                RType rtype;                            // 消息类型
                std::string rid;                        // 消息id
                std::promise<xu::BaseMessage::Ptr> res; // 结果
                Callback cb;                            // 回调函数
                bool _is_rsp;                           //该请求是否被响应
            };
            Requestor()
            {}
            

            // 作为响应回调
            void OnRequest(const xu::BaseConnection::Ptr &conn, const xu::BaseMessage::Ptr &msg)
            {
                // 1.通过rid找到对应的请求
                auto it = GetDescribe(msg->Id());
                if (it.get() == nullptr)
                {
                    LOG(LogLevel::ERROR) << "找不到对应的请求";
                    return;
                }

                // 2.根据不同类型执行不同操作
                if (it->rtype == RType::REQ_ASYNC)
                {
                    it->res.set_value(msg);
                }
                else if (it->rtype == RType::REQ_CALLBACK)
                {
                    if (it->cb == nullptr)
                    {
                        LOG(LogLevel::ERROR) << "回调函数没设置";
                    }

                    it->cb(msg);
                }
                else
                {
                    LOG(LogLevel::ERROR) << "未知类型错误";
                }

                it->_is_rsp = true;
                // 4.拿掉该请求
                DelDescribe(msg->Id());
            }

            // 异步
            bool Send(const xu::BaseConnection::Ptr &conn, const xu::BaseMessage::Ptr &msg, Async &res)
            {
                // 1.创建一个请求
                auto ret = NewDescribe(msg, RType::REQ_ASYNC);
                if (ret.get() == nullptr)
                {
                    LOG(LogLevel::ERROR) << "构建请求失败";
                    return false;
                }
                // 2.获取异步
                res = ret->res.get_future();
                // 3.发送数据
                conn->Send(msg);

                return true;
            }
            // 同步
            bool Send(const xu::BaseConnection::Ptr &conn, const xu::BaseMessage::Ptr &msg, xu::BaseMessage::Ptr &res)
            {
                // 1.利用异步
                Async ret_async;
                bool ret = Send(conn, msg, ret_async);
                if (ret == false)
                {
                    return false;
                }
                // 2.阻塞等待结果
                LOG(LogLevel::DEBUG)<<"同步阻塞等待结果中";
                if(ret_async.wait_for(std::chrono::seconds(3)) == std::future_status::timeout)
                {
                    LOG(LogLevel::WARNING) << "同步请求结果超时" ;
                    DelDescribe(msg->Id());
                    conn->ShutDown();
                    return false;
                }
                res = ret_async.get();

                return true;
            }
            // 回调
            bool Send(const xu::BaseConnection::Ptr &conn, const xu::BaseMessage::Ptr &msg, const Callback &cb)
            {
                // 1.创建一个请求
                auto ret = NewDescribe(msg, RType::REQ_CALLBACK, cb);
                if (ret.get() == nullptr)
                {
                    LOG(LogLevel::ERROR) << "构建请求失败";
                    return false;
                }

                // 2.进行发送数据
                conn->Send(msg);
                return true;
            }

            void setDelClient(OfflineCallback obc)
            {
                _obc = obc;
            }

        private:
            RequestDescribe::Ptr NewDescribe(const xu::BaseMessage::Ptr req, const RType &rtype, const Callback &cb = Callback())
            {
                std::unique_lock<std::mutex> _lock(_mutex);
                auto desc = std::make_shared<RequestDescribe>();
                desc->rid = req->Id();
                desc->rtype = rtype;
                desc->_is_rsp = false;

                if (rtype == RType::REQ_CALLBACK)
                {
                    desc->cb = cb;
                }

                _req_desc.insert(std::make_pair(req->Id(), desc));

                return desc;
            }

            RequestDescribe::Ptr GetDescribe(const std::string &rid)
            {
                std::unique_lock<std::mutex> _lock(_mutex);
                auto it = _req_desc.find(rid);
                if (it == nullptr)
                {
                    return RequestDescribe::Ptr();
                }

                return it->second;
            }

            void DelDescribe(const std::string &rid)
            {
                LOG(LogLevel::DEBUG) <<"移除id : " <<rid;
                std::unique_lock<std::mutex> _lock(_mutex);
                _req_desc.erase(rid);
            }

        private:
            std::mutex _mutex;
            std::unordered_map<std::string, RequestDescribe::Ptr> _req_desc;
            OfflineCallback _obc;
        };

    };

};